﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CreateElevationViewAction.h"
#include "IUiDocument.h"
#include "IUiView.h"
#include "IPickPointAction.h"
#include "Vector3dUtils.h"
#include "IModelView.h"
#include "IElementBasicInformation.h"
#include "GbmpSwitchViewActionRequest.h"

#include "IUserTransaction.h"
#include "IGraphicsLine.h"
#include "IGraphicsElementShape.h"

#include "IDocument.h"
#include "IRegenerator.h"
#include "ILine3d.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

#define NEW_ELEVATION_VIEW_NAME_PREFIX    GBMP_TR(L"新立面视图")

namespace
{
    //////////////////////////////////////////////////////////////////////////
    class CreateDefaultRectViewPortBatchDataChangeRequestor : public IBatchDataChangeRequest
    {
    public:
        CreateDefaultRectViewPortBatchDataChangeRequestor(IDocument* pDoc, IModelView* pModelView) :
            m_pDoc(pDoc), m_pModelView(pModelView)
        {
        }

        ~CreateDefaultRectViewPortBatchDataChangeRequestor()
        {
        }

    public:
        bool Execute() override
        {
            m_pModelView->CreateDefaultRectViewport(15000, 15000, 12000, 12000);
            return true;
        }

    private:
        IDocument* m_pDoc;
        IModelView* m_pModelView;
    };
}

CreateElevationViewAction::CreateElevationViewAction()
    : m_isUserCancelled(false)
{
    m_actionStatus = CEV_NOT_STARTED;
}

CreateElevationViewAction::~CreateElevationViewAction()
{

}


void CreateElevationViewAction::ActionCancelled()
{
    //通知基类，会标记当前Action结束
    ActionBase::ActionCancelled();
}

void CreateElevationViewAction::InitAction( IUiView* pCurrentView )
{
    EnterGettingStartPointState();
}

void CreateElevationViewAction::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    if(m_actionStatus == CEV_GETTING_START_POINT)
    {
        if(m_isUserCancelled)
        {
            // 如果用户在画第一个点时就选择退出，那么就退出整个命令
            MarkFinishStatus(ActionFinishStatus::Successful);
            UpdateView();
            return;
        }
        EnterGettingEndPointState();
    }
    else if (m_actionStatus == CEV_GETTING_END_POINT)
    {
        if(m_isUserCancelled)
        {
            // 如果用户在画第二个点时选择退出，那么先退到画第一个点的状态
            EnterGettingStartPointState();
            UpdateView();
            return;
        }

        gcmp::OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(GetDoc(), GBMP_TR(L"创建立面视图"));
        CreateElevationView(pCurrentView, m_startPt, m_endPt);
        ut->Commit();

        UpdateView();
    }
}

void CreateElevationViewAction::CreateElevationView(IUiView* pCurrentView,
    const Vector3d& startPoint, const Vector3d& endPoint)
{
    static int count = 1;
    GbmpString viewName;
    viewName << NEW_ELEVATION_VIEW_NAME_PREFIX << count++;

    IUiDocument* pUIDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc, L"pUIDoc不能为空",L"GDMPLab",L"2024-03-30");
    IDocument* document = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(document, L"document不能为空",L"GDMPLab",L"2024-03-30");
    IModelView* pCurModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurModelView, L"pCurModelView不能为空",L"GDMPLab",L"2024-03-30");

    Vector3d viewDirection, origin, rightDirection, upDirection;
    rightDirection = endPoint - startPoint;
    rightDirection.Normalize();
    viewDirection = rightDirection.Cross(pCurModelView->GetViewDirection());
    upDirection = -pCurModelView->GetViewDirection();
    origin = (startPoint + endPoint) / 2.0;

    IModelView* pElevationView = IModelView::Create(document, viewName.getString(), BuiltInViewType::TwoDimensional, viewDirection, origin, rightDirection, upDirection);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElevationView, L"创建pElevationView失败",L"GDMPLab",L"2024-03-30");
    pElevationView->SetUserDataId(L"ElevationViewType");


    CreateDefaultRectViewPortBatchDataChangeRequestor batchDataChangeRequestor(document, pElevationView);
    document->GetRegenerator()->BatchDataChange(&batchDataChangeRequestor);

    pElevationView->GetDocument()->GetRegenerator()->RegenerateElement(pElevationView->GetElementId());

    ElementId id = pElevationView->GetBasicInformation()->GetElementId();
    DBG_WARN_AND_RETURN_VOID_UNLESS(id.IsValid(), L"invalid object id",L"GDMPLab",L"2024-03-30");

    PostRequest(NEW_AS_OWNER_PTR(GbmpSwitchViewActionRequest, id));
}

void CreateElevationViewAction::OnPointUpdate(IUiView* pCurrentView, const gcmp::Vector3d& pos, const gcmp::Vector3d& mousePt)
{
    OnLineUpdated(pCurrentView, m_startPt, pos);
}

void CreateElevationViewAction::DrawTempLine(IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"无效输入参数pCurrentView",L"GDMPLab",L"2024-03-30");

    if (Vector3dUtils::IsEqual(startPt,endPt))
    {
        return;
    }

    OwnerPtr<IGraphicsElementShape> opResultGrep = IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObject);
    {
        OwnerPtr<ILine3d> opLine3d = ILine3d::Create(startPt, endPt);
        gcmp::OwnerPtr<gcmp::IGraphicsCurve3d> opLine = IGraphicsCurve3d::Create(opLine3d.get());
        opResultGrep->AddChild(TransferOwnership(opLine->Clone()));
    }
    DrawTempGraphicsElementShape(TransferOwnership(opResultGrep));
}

void CreateElevationViewAction::OnLineUpdated(IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt)
{
    DrawTempLine(pCurrentView, startPt, endPt);
}

void CreateElevationViewAction::EnterGettingStartPointState()
{
    m_actionStatus = CEV_GETTING_START_POINT;
    SetPromptMessage(GBMP_TR(L"选择视图位置"));
    StartChildAction(IPickPointAction::Create( 
        PickPointExchangeData(&m_startPt, &m_isUserCancelled, &m_pickedPoints),
        nullptr));
}

void CreateElevationViewAction::EnterGettingEndPointState()
{
    m_actionStatus = CEV_GETTING_END_POINT;
    SetPromptMessage(GBMP_TR(L"输入终止点确定视图方向"));

    OwnerPtr<IPickPointAction> oPickAction = IPickPointAction::Create( 
        PickPointExchangeData(&m_endPt, &m_isUserCancelled, &m_pickedPoints)
        , IPickPointAction::CreateMoveCallback(&CreateElevationViewAction::OnPointUpdate, this));
    oPickAction->SetFirstPoint(m_startPt);
    StartChildAction(TransferOwnership(oPickAction));
}



